package cn.chenxinjie.hrm.service.impl;

import cn.chenxinjie.hrm.constant.CourseTypeConstant;
import cn.chenxinjie.hrm.domain.CourseType;
import cn.chenxinjie.hrm.mapper.CourseTypeMapper;
import cn.chenxinjie.hrm.service.ICourseTypeService;
import cn.chenxinjie.hrm.util.AjaxResult;
import cn.chenxinjie.hrm.vo.CourseVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 课程目录 服务实现类
 *
 * @author chenxinjie
 * @since 2022-03-12
 */
@Service
public class CourseTypeServiceImpl_redis extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {

    @Autowired
    private CourseTypeMapper courseTypeMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    private Lock lock = new ReentrantLock();

    @Override
    public AjaxResult treeData() {
        /*
            通过redis缓存课程名称,每次查询数据的时候先查询redis,如果redis中没有再查询数据库,如果有就直接返回数据.
         */
        Object obj = redisTemplate.opsForValue().get(CourseTypeConstant.COURSE_TYPE_TREE_DATA);
        List<CourseType> list = new ArrayList<>();
        if (obj != null) {
            list = (List<CourseType>) obj;
            System.out.println("课程类型:缓存中获取");
        } else {
            if (lock.tryLock()) {
                try {
                    list = loadTreeData();
                    System.out.println("课程类型:数据库中获取");
                    int random = ThreadLocalRandom.current().nextInt(100, 200);
                    redisTemplate.opsForValue().set(CourseTypeConstant.COURSE_TYPE_TREE_DATA,list,random, TimeUnit.MINUTES);
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } else {
                try {
                    Thread.sleep(200);
                    treeData();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        // 通过sql封装数据
        //List<CourseType> list = courseTypeMapper.treeData();
        return AjaxResult.me().setResultObj(list);
    }

    @Override
    public AjaxResult getCrumbs(Long typeId) {
        // 根据id查询到自己的全部数据
        CourseType courseType= courseTypeMapper.selectById(typeId);
        // 拿到自己的path然后用点号进行分割就能找到自己的全部父级
        String path = courseType.getPath();
        String[] ids = path.split("\\.");
        // 遍历数组,找到父级本身的信息和他所属同一级的其他数据信息
        ArrayList<CourseVo> list = new ArrayList<>();
        for (String id : ids){
            // 通过id查询父级本身的信息
            CourseType own = courseTypeMapper.selectById(id);
            // 准备一个wrapper对象来封装查询条件
            Wrapper<CourseType> wrapper = new EntityWrapper<>();
            wrapper.eq("pid",own.getPid()).and().ne("id",own.getId());
            // 查询所属同一级的信息
            List<CourseType> bros = courseTypeMapper.selectList(wrapper);
            CourseVo courseVo = new CourseVo();
            courseVo.setOwn(own).setBros(bros);
            list.add(courseVo);
        }
        return AjaxResult.me().setResultObj(list);
    }

    private List<CourseType> loadTreeData() {
        ArrayList<CourseType> result = new ArrayList<>();
        List<CourseType> types = courseTypeMapper.selectList(null);
        // 组装关系 子级的pid等于父级的id
        HashMap<Long, CourseType> map = new HashMap<>();
        types.stream().forEach(type -> {
            map.put(type.getId(),type);
        });
        types.stream().forEach(type -> {
            // 如果type的pid为0 说明是第一层级
            if (type.getPid() == 0) {
                result.add(type);
            }else{
                CourseType parent = map.get(type.getPid());
                parent.getChildren().add(type);
            }
        });
        return result;
    }

    @Override
    public boolean insert(CourseType entity) {
        boolean b = super.insert(entity);
        redisTemplate.delete(CourseTypeConstant.COURSE_TYPE_TREE_DATA);
        return b;
    }

    @Override
    public boolean updateById(CourseType entity) {
        boolean b = super.updateById(entity);
        redisTemplate.delete(CourseTypeConstant.COURSE_TYPE_TREE_DATA);
        return b;
    }

    @Override
    public boolean deleteById(Serializable id) {
        redisTemplate.delete(CourseTypeConstant.COURSE_TYPE_TREE_DATA);
        boolean b = super.deleteById(id);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        redisTemplate.delete(CourseTypeConstant.COURSE_TYPE_TREE_DATA);
        return b;
    }
}
